package com.hedl.practice.diyJava.data.date_calendar.test;

import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) {

        int n = 123400;

        //123400
        System.out.println(n);
        //1e208
        System.out.println(Integer.toHexString(n));
        //$123,400.00
        //数字格式类,方法获取货币实例,传入本地化。美元表达式，指定格式化数字
        System.out.println(NumberFormat.getCurrencyInstance(Locale.US).format(n));

        System.out.println("============================================================");

        /**
         * 理解了数据的存储和展示，我们回头看看以下几种日期和时间：
         *      2019-11-20 0:15:01 GMT+00:00
         *      2019年11月20日8:15:01
         *      11/19/2019 19:15:01 America/New_York
         * 它们实际上是数据的展示格式，分别按英国时区、中国时区、纽约时区对同一个时刻进行展示。
         * 而这个“同一个时刻”在计算机中存储的本质上只是一个整数，我们称它为Epoch Time。
         *
         * Epoch Time是计算从1970年1月1日零点（格林威治时区／GMT+00:00）到现在所经历的秒数，例如：
         * 1574208900表示从1970年1月1日零点GMT时区到该时刻一共经历了1574208900秒，换算成伦敦、北京和纽约时间分别是：
         *
         * 1574208900 = 北京时间2019-11-20 8:15:00
         *            = 伦敦时间2019-11-20 0:15:00
         *            = 纽约时间2019-11-19 19:15:00
         *
         * Epoch Time又称为时间戳，在不同的编程语言中，会有几种存储方式：
         *      以秒为单位的整数：1574208900，缺点是精度只能到秒；
         *      以毫秒为单位的整数：1574208900123，最后3位表示毫秒数；
         *      以秒为单位的浮点数：1574208900.123，小数点后面表示零点几秒。
         *
         * 在Java程序中，时间戳通常是用long表示的毫秒数，即
         */
        long t = 1574208900123L;
        System.out.println(System.currentTimeMillis());     //获取当前时间戳

        System.out.println("=========================标准库API==================");
        /**
         * Java标准库有两套处理日期和时间的API：
         *      一套定义在java.util这个包里面，主要包括Date、Calendar和TimeZone这几个类；
         *      一套新的API是在Java 8引入的，定义在java.time这个包里面，主要包括LocalDateTime、ZonedDateTime、ZoneId等。
         */

        /**
         * 注意getYear()返回的年份必须加上1900，getMonth()返回的月份是0~11分别表示1~12月，所以要加1，
         * 而getDate()返回的日期范围是1~31，又不能加1
         */
        //旧api的使用:Date的使用
        //获取当前时间
        Date date = new Date();
        System.out.print(date.getYear()+1900+"-");        // 必须加上1900
        System.out.print(date.getMonth()+1+"-");      // 0~11，必须加上1
        System.out.println(date.getDate());     // 1~31，不能加1

        // 转换为String:
        System.out.println("转换为String:"+date.toString());
        // 转换为GMT时区:
        System.out.println("转换为GMT时区:"+date.toGMTString());
        // 转换为本地时区:
        System.out.println("转换为本地时区:"+date.toLocaleString());

        System.out.println("============================自定义格式输出时间===========================");
        /**
         * 打印本地时区表示的日期和时间时，不同的计算机可能会有不同的结果。
         * 如果我们想要针对用户的偏好精确地控制日期和时间的格式，就可以使用SimpleDateFormat对一个Date进行转换。
         * 它用预定义的字符串表示格式化：
         *      yyyy：年
         *      MM：月
         *      dd: 日
         *      HH: 小时
         *      mm: 分钟
         *      ss: 秒
         */
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("格式一："+simpleDateFormat.format(date));

        /**
         * 上述代码在不同的语言环境会打印出类似Sun Sep 15, 2019这样的日期。可以从JDK文档查看详细的格式说明。
         * 一般来说，字母越长，输出越长。以M为例，假设当前月份是9月：
         *      M：输出9
         *      MM：输出09
         *      MMM：输出Sep
         *      MMMM：输出September
         *
         *Date对象有几个严重的问题：它不能转换时区，除了toGMTString()可以按GMT+0:00输出外，Date总是以当前计算机系统的默认时区为基础进行输出。
         *  此外，我们也很难对日期和时间进行加减，计算两个日期相差多少天，计算某个月第一个星期一的日期等。
         */
        SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("E MMM dd, yyyy");
        System.out.println("格式二："+simpleDateFormat1.format(date));

        System.out.println("======================Calendar======================");

        /**
         * Calendar可以用于获取并设置年、月、日、时、分、秒，它和Date比，主要多了一个可以做简单的日期和时间运算的功能。
         *      Calendar.YEAR               年
         *      Calendar.MONTH              月；需要加1
         *      Calendar.DAY_OF_MONTH       日
         *      Calendar.DAY_OF_WEEK        周几
         *      Calendar.HOUR_OF_DAY        时
         *      Calendar.MINUTE             分
         *      Calendar.SECOND             秒
         *      Calendar.MILLISECOND        毫秒
         *
         *注意到Calendar获取年月日这些信息变成了get(int field)，返回的年份不必转换，
         * 返回的月份仍然要加1，返回的星期要特别注意，1~7分别表示周日，周一，……，周六。
         *
         * Calendar只有一种方式获取，即Calendar.getInstance()，
         * 而且一获取到就是当前时间。如果我们想给它设置成特定的一个日期和时间，就必须先清除所有字段：
         */
        //获取当前时间
        Calendar c = Calendar.getInstance();
        int y = c.get(Calendar.YEAR);       //年
        int m = c.get(Calendar.MONTH)+1;    //月
        int d = c.get(Calendar.DAY_OF_MONTH);   //日
        int w = c.get(Calendar.DAY_OF_WEEK);    //周几
        int hh = c.get(Calendar.HOUR_OF_DAY);   //时
        int mm = c.get(Calendar.MINUTE);    //分
        int ss = c.get(Calendar.SECOND);    //秒
        int ms = c.get(Calendar.MILLISECOND);   //毫秒
        System.out.println(y + "-" + m + "-" + d + " " + w + " " + hh + ":" + mm + ":" + ss + "." + ms);

        System.out.println("===============================使用Calendar指定时间===============================");
        //清除所有
        c.clear();
        //设置时间2019年
        c.set(Calendar.YEAR,2019);
        // 设置9月:注意8表示9月:
        c.set(Calendar.MONTH,8);        //因为月份需要加1；因为这里我们需要写9月份，所以我们便捷一点，直接不加一，直接写成8，间接等于9月
        // 设置2日:
         c.set(Calendar.DAY_OF_MONTH,2);        //日
        // 设置时间:
        c.set(Calendar.HOUR_OF_DAY,21);     //时
        c.set(Calendar.MINUTE,20);      //分
        c.set(Calendar.SECOND,30);      //秒
        /**
         * 利用Calendar.getTime()可以将一个Calendar对象转换成Date对象，然后就可以用SimpleDateFormat进行格式化了。
         */
        System.out.println("自定义时间在几点显示："+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(c.getTime()));

        System.out.println("======================================TimeZone==================================");
        /**
         * TimeZone提供了时区转换的功能。时区用TimeZone对象表示
         *
         */
        TimeZone tzDefault = TimeZone.getDefault();      //获取当前时间
        TimeZone tzGMT9 = TimeZone.getTimeZone("GMT+09:00");        //GMT+9:00时区
        TimeZone tzNY = TimeZone.getTimeZone("America/New_York");       //纽约时区
        System.out.println("Asia/Shanghai："+tzDefault.getID());      //Asia/Shanghai
        System.out.println("GMT+09:00："+tzGMT9.getID());     //GMT+09:00
        System.out.println("America/New_York："+tzNY.getID());       //America/New_York
        String[] ids = TimeZone.getAvailableIDs();
        for (String id : ids) {
            System.out.println("列出系统支持的所有ID："+id);
        }

        /**
         * 我们就可以对指定时间进行转换。例如，下面的例子演示了如何将北京时间2019-11-20 8:15:00转换为纽约时间：
         */
        System.out.println("=======================================================");
        Calendar c1 = Calendar.getInstance();
        c1.clear();
        c1.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));      //设置时区
        c1.set(2019,10 /* 11月 */,20,8,15,0);    //自定义时间
        //显示时间
        SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");       //自定义时间格式
        simpleDateFormat2.setTimeZone(TimeZone.getTimeZone("America/New_York"));        //把自定义的格式转换成美国纽约时间
        System.out.println(simpleDateFormat2.format(c1.getTime()));      //把自定义的时间按照纽约时区输出

        /**
         * 利用Calendar进行时区转换的步骤是：
         *      清除所有字段；
         *      设定指定时区；
         *      设定日期和时间；
         *      创建SimpleDateFormat并设定目标时区；
         *      格式化获取的Date对象（注意Date对象无时区信息，时区信息存储在SimpleDateFormat中）
         *          本质上时区转换只能通过SimpleDateFormat在显示的时候完成。
         */
        System.out.println("===============Calendar也可以对日期和时间进行简单的加减：=======================");

        Calendar c2 = Calendar.getInstance();
        c2.clear();
        c2.set(2019, 10 /* 11月 */, 20, 8, 15, 0);
        // 加5天并减去2小时:
        c2.add(Calendar.DAY_OF_MONTH,5);
        c2.add(Calendar.HOUR_OF_DAY,-2);
        //显示时间
        SimpleDateFormat simpleDateFormat3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date time = c2.getTime();
        System.out.println(simpleDateFormat3.format(time));    //愿时间：2019-11-20 08:15:00 现在：2019-11-25 06:15:00

        /**
         * 小结：
         *      计算机表示的时间是以整数表示的时间戳存储的，即Epoch Time，Java使用long型来表示以毫秒为单位的时间戳，通过System.currentTimeMillis()获取当前时间戳。
         *Java有两套日期和时间的API：
         *      旧的Date、Calendar和TimeZone；
         *      新的LocalDateTime、ZonedDateTime、ZoneId等。
         * 分别位于java.util和java.time包中。
         */
    }
}
